package cc.itcast.netty.c1;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;

public class HelloServer {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ChannelGroup channelGroup = null;
        try {
            channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

            ServerBootstrap b = new ServerBootstrap();
            ChannelGroup finalChannelGroup1 = channelGroup;
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new StringDecoder());
                            p.addLast(new StringEncoder());
                            p.addLast(new ChannelInboundHandlerAdapter() {
                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    Thread.sleep(1000);
                                    String sub1 = msg.toString().substring(0, 4);//设备编号
                                    String sub2 = msg.toString().substring(4, 9);//具体数据hello
                                    String sub3 = msg.toString().substring(9, 13);//校验码
                                    String crc177 = CRC17(msg.toString().substring(0, 9));
                                    if (sub3.equals(crc177)) {
                                        System.out.println("接收到设备" + sub1 + "上传数据:" + sub2 + "  当前时间:" + LocalDateTime.now());
                                        // 准备响应数据（这里假设我们想要发送一个简单的"OK"消息）
                                        String responseMessage = "200";
                                        ByteBuf buf = Unpooled.copiedBuffer(responseMessage, StandardCharsets.UTF_8);

                                        // 直接发送字节数据给客户端
                                        ctx.writeAndFlush(buf);
                                    }else {
                                        System.out.println("校验失败");
                                    }
                                }

                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                    // 当新的连接建立时，添加到channelGroup中
                                    finalChannelGroup1.add(ctx.channel());
                                    super.channelActive(ctx);
                                }

                                @Override
                                public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                                    // 当连接断开时，从channelGroup中移除
                                    finalChannelGroup1.remove(ctx.channel());
                                    super.channelInactive(ctx);
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    cause.printStackTrace();
                                    ctx.close();
                                }
                            });
                        }
                    });

            // 绑定端口并启动服务器
            ChannelFuture f = b.bind(8080).sync();

            // 打印当前连接数的线程
            ChannelGroup finalChannelGroup = channelGroup;
            new Thread(() -> {
                while (true) {
                    System.out.println("当前客户端连接数: " + finalChannelGroup.size());
                    try {
                        Thread.sleep(5000); // 每5秒打印一次
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

            // 等待服务器通道关闭
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            // 关闭channelGroup（这实际上不是必要的，因为当EventLoopGroup关闭时，它会自动关闭）
            channelGroup.close().sync();
            // 优雅地关闭线程组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

//        new ServerBootstrap()
//                .group(new NioEventLoopGroup())
//                .channel(NioServerSocketChannel.class)
//                .childHandler(new ChannelInitializer<NioSocketChannel>() {
//                    @Override
//                    protected void initChannel(NioSocketChannel ch) throws Exception {
//                        ch.pipeline().addLast(new StringDecoder());
//                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
//                            @Override
//                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//                                System.out.println(msg);
//                            }
//                        });
//                    }
//                })
//                .bind(8080);


    }
//    private static String bytesToHex(byte[] bytes, int length) {
//        StringBuilder hexString = new StringBuilder(2 * length);
//        for (int i = 0; i < length; i++) {
//            String hex = Integer.toHexString(0xff & bytes[i]);
//            if (hex.length() == 1) {
//                hexString.append('0');
//            }
//
//            hexString.append(hex);
//        }
//        return hexString.toString();
//    }

    public static String CRC17(String temp) {

        Integer[] regs = new Integer[temp.length()];
        for (int i = 0; i < temp.length(); i++) {
            regs[i] = (int)temp.charAt(i);
        }
        int por = 0xFFFF;
        for (int j = 0; j < regs.length; j++) {
            por = por >> 8;
            por ^= regs[j];
            for (int i = 0; i < 8; i++) {
                if ((por & 0x01) == 1) {
                    por = por >> 1;
                    por = por ^ 0xa001;
                } else
                    por = por >> 1;
            }
        }
        return Integer.toHexString(por);
    }
}
